/**
 * @Author      : xingnan
 * @Email       : 457415936@qq.com
 * @Time        : 16:58
 * @File        : fs.go
 * @Project     : toolbox
 * @Description : 文件操作
 */
package com

import (
	"bufio"
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"strings"
)

// 文件目录是否存在
func PathDirExists(p string) bool {
	st, err := os.Stat(p)
	if err != nil {
		return false
	}
	return st.IsDir()
}

// 路径是否存在
func PathExists(p string) bool {
	if _, err := os.Stat(p); os.IsNotExist(err) {
		return false
	}
	return true
}

// 读取文件第一行
func ReadFileFirstLine(path string) (string, error) {
	file, err := os.Open(path)
	if err != nil {
		return "", err
	}
	defer file.Close()
	reader := bufio.NewReader(file)
	var part []byte
	var prefix bool
	buffer := bytes.NewBuffer(make([]byte, 0, 512))
	for {
		if part, prefix, err = reader.ReadLine(); err != nil {
			return "", err
		}
		if part == nil {
			return "", os.ErrInvalid
		}
		buffer.Write(part)
		if !prefix {
			return buffer.String(), nil
		}
	}
}

// 逐行读取
// offset 开始偏移量
// 读取行数，从偏移量offset开始
//   n >= 0: 最多 n 行
//   n < 0: 整个文件
func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) {
	f, err := os.Open(filename)
	if err != nil {
		return []string{""}, err
	}
	defer f.Close()

	var ret []string

	r := bufio.NewReader(f)
	for i := 0; i < n+int(offset) || n < 0; i++ {
		line, err := r.ReadString('\n')
		if err != nil {
			break
		}
		if i < int(offset) {
			continue
		}
		ret = append(ret, strings.Trim(line, "\n"))
	}

	return ret, nil
}

// 文件类型
func FileType(file string) string {
	SplitType := strings.Split(strings.ToLower(file), ".")
	LenCount := len(SplitType)
	return strings.TrimSpace(SplitType[LenCount-1])
}

/*
	@name 计算文件行数
	@param filepath		string	文件路径
	@return				int64	行数
	@return				error	错误类型
*/
func CountFileLine(name string) (int64, error) {
	data, err := ioutil.ReadFile(name)
	if err != nil {
		return 0, err
	}
	count := int64(0)
	for i := 0; i < len(data); i++ {
		if data[i] == '\n' {
			count++
		}
	}
	return count, nil
}

// 逐行读取
func ReadLines(path string) ([]string, int, error) {
	readLines, err := ReadLinesOffsetN(path, 0, -1)
	return readLines, len(readLines), err
}

// 文件重命名
func Rename(file string, to string) bool {
	err := os.Rename(file, to)
	if err == nil {
		return true
	} else {
		return false
	}
}

// 删除文件
func DelFile(file string) bool {
	if err := os.Remove(file); err == nil {
		return true
	} else {
		return false
	}
}

// 读取定行文件
func ReadStringForLine(path string, lineNumber int) string {
	file, _ := os.Open(path)
	fileScanner := bufio.NewScanner(file)
	lineCount := 1
	for fileScanner.Scan() {
		if lineCount == lineNumber {
			return fileScanner.Text()
		}
		lineCount++
	}
	defer file.Close()
	return ""
}

// 读取文本行数
func ReadLineCounter(path string) (int64, error) {

	var readSize int
	var err error
	var count int64

	f, err := os.Open(path)
	defer f.Close()
	if err != nil {
		return 0, err
	}
	reader := bufio.NewReader(f)

	buf := make([]byte, 1024)

	for {
		readSize, err = reader.Read(buf)
		if err != nil {
			break
		}

		var buffPosition int
		for {
			i := bytes.IndexByte(buf[buffPosition:], '\n')
			if i == -1 || readSize == buffPosition {
				break
			}
			buffPosition += i + 1
			count++
		}
	}
	if readSize > 0 && count == 0 || count > 0 {
		count++
	}
	if err == io.EOF {
		return count, nil
	}

	return count, err
}

// 读取文本文件
func ReadFile(path string) string {
	fi, err := os.Open(path)
	if err != nil {
		// panic(err)
		return ""
	}
	defer fi.Close()
	fd, err := ioutil.ReadAll(fi)

	return string(fd)
}

// 读取文件
func ReadFileByte(path string) ([]byte, error) {
	fi, err := os.Open(path)
	if err != nil {
		// panic(err)
		return []byte(""), err
	}
	defer fi.Close()
	return ioutil.ReadAll(fi)
}

// 检查文件或目录是否存在
// 如果由 filename 指定的文件或目录存在则返回 true，否则返回 false
func PathExist(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil || os.IsExist(err)
}

// 检查文件或目录是否存在
// 如果由 filename 指定的文件或目录存在则返回 true，否则返回 false
func FileExist(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil || os.IsExist(err)
}

// 字符串写入文件
func WriteFile(fullpath, str string) error {
	data := []byte(str)
	return ioutil.WriteFile(fullpath, data, 0644)
}

// 字节写入文件
func WriteByteFile(fullpath string, data []byte) error {
	return ioutil.WriteFile(fullpath, data, 0644)
}
